#pragma once

#include <functional>
#include <vector>
#include <atomic>
#include <memory>
#include <mutex>

#include "noncopyable.h"
#include "Timestamp.h"
#include "CurrentThread.h"

class Channel;
class Poller;

// 事件循环类 主要包含两个大模块 Channel Poller(epoll muduo实现了poll和epoll)
// 一个事件循环包含一个poller和一个channel列表，一个poller管着一堆channel
// EventLoop相当于Reactor反应堆，至少有一个mainReactor
class EventLoop : noncopyable
{
public:
    using Functor = std::function<void()>;

    EventLoop();
    ~EventLoop();

    // 开启事件循环
    void loop();
    // 退出事件循环
    void quit();

    Timestamp pollReturnTime() const { return pollReturnTime_; }

    // 在当前loop中执行cb
    void runInLoop(Functor cb);
    // 把cb放到队列中，唤醒loop所在的线程，执行cb
    void queueInLoop(Functor cb);

    // 用来唤醒loop所在的线程
    void wakeup();  // mainReactor 唤醒 subReactor

    // EventLoop的方法 → Poller的方法
    // 更新Channel
    void updateChannel(Channel* channel);
    // 删除Channel
    void removeChannel(Channel* channel);
    bool hasChannel(Channel* channel);

    // 判断EventLoop对象是否在自己的线程里面
    bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); /*创建这个EventLoop的线程id和当前线程id比较，看是不是在创建线程中*/}

private:
    void handleRead();  // wake up 的可读事件函数，构造函数中设给wakeupChannel_
    void doPendingFunctors();  // 执行回调，回调都在pendingFunctors_(vec)里放着

    using ChannelList = std::vector<Channel*>;

    std::atomic_bool looping_;  // 原子操作，底层通过CAS实现
    std::atomic_bool quit_;  // 标志退出loop循环
    
    const pid_t threadId_;  // 记录当前loop所在的线程id
    
    Timestamp pollReturnTime_;  // poller返回发生事件的channels的时间点
    std::unique_ptr<Poller> poller_;

    int wakeupFd_;  // 主要作用：当mainReactor获取一个新用户的channel，通过轮询算法选择一个subReactor，通过该成员唤醒subReactor处理
    std::unique_ptr<Channel> wakeupChannel_;

    ChannelList activeChannels_;  // std::vector<Channel*> activeChannels_，发生事件的Channels
    // Channel* currentActiveChannel_;

    std::atomic_bool callingPendingFunctors_;  // 标志当前loop是否有需要执行的回调操作
    std::vector<Functor> pendingFunctors_;  // 存储loop需要执行的所有回调操作
    std::mutex mutex_;  // 互斥锁，用来保护pendingFunctors_容器的线程安全操作
};